package com.itheima.stock.task.impl;

import com.google.common.collect.Lists;
import com.itheima.stock.common.domain.StockInfoConfig;
import com.itheima.stock.mapper.StockBusinessMapper;
import com.itheima.stock.mapper.StockMarketIndexInfoMapper;
import com.itheima.stock.mapper.StockRtInfoMapper;
import com.itheima.stock.pojo.StockMarketIndexInfo;
import com.itheima.stock.task.StockTimerTaskService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.utils.IdWorker;
import com.itheima.stock.utils.ParseType;
import com.itheima.stock.utils.ParserStockInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


@Service("stockTimerTaskService")
@Slf4j
public class StockTimerTaskServiceImpl implements StockTimerTaskService {

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private ParserStockInfoUtil parserStockInfoUtil;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    //采集国内大盘实时数据方法
    @Override
    public void getInnerMarketInfo() {
        //1.组装请求地址:http://hq.sinajs.cn/list=s_sh000001,sz399001
        String url = stockInfoConfig.getMarketUrl()+String.join(",",stockInfoConfig.getInner());
        //2.组装请求对象
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer","http://finance.sina.com.cn/realstock/company/sh000001/nc.shtml");
        headers.add("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36");
        HttpEntity<Object> httpEntity = new HttpEntity<>(headers);
        //3.发送数据 获取响应结果
        ResponseEntity<String> respEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
        //获取响应数据
        String respStr = respEntity.getBody();
        System.out.println(respStr);
        //4.解析数据，并将数据封装到实体对象下
        //4.1提取正则表达式
        String reg = "var hq_str_(.*)=\"(.*)\";";
        //4.2编译表达式
        Pattern pattern = Pattern.compile(reg);
        //4.3匹配字符串
        Matcher matcher = pattern.matcher(respStr);
        //定义存放采集数据的集合
        List<StockMarketIndexInfo> infos = new ArrayList<>();
        //4.4获取正则组数据
        while (matcher.find()) {
            //获取大盘的code
            String marketCode = matcher.group(1);
            //获取其它信息，字符串以逗号间隔
            String otherInfo=matcher.group(2);
            //以逗号切割字符串，形成数组
            String[] splitArr = otherInfo.split(",");
            //大盘名称
            String marketName=splitArr[0];
            //获取当前大盘的点数
            BigDecimal openPoint=new BigDecimal(splitArr[1]);
            //获取大盘的涨跌值
            BigDecimal preClosePoint=new BigDecimal(splitArr[2]);
            //获取大盘的涨幅
            BigDecimal curPoint=new BigDecimal(splitArr[3]);
            //获取大盘最高点
            BigDecimal maxPoint=new BigDecimal(splitArr[4]);
            //获取大盘的di
            BigDecimal minPoint=new BigDecimal(splitArr[5]);
            //获取成交量
            Long tradeAmt=Long.valueOf(splitArr[8]);
            //获取成交金额
            BigDecimal tradeVol=new BigDecimal(splitArr[9]);
            //时间
            String dateTime = splitArr[30] + " " + splitArr[31];
            Date curTime = DateTimeUtil.getDateTimeWithoutSecond(splitArr[30] + " " + splitArr[31]).toDate();
            //组装大盘实体对象
            StockMarketIndexInfo marketIndexInfo = StockMarketIndexInfo.builder()
                    .id(idWorker.nextId() + "")
                    .marketCode(marketCode).curTime(curTime)
                    .marketName(marketName).preClosePoint(preClosePoint)
                    .openPoint(openPoint).curPoint(curPoint)
                    .minPoint(minPoint).maxPoint(maxPoint)
                    .tradeAmount(tradeAmt).tradeVolume(tradeVol)
                    .build();
            infos.add(marketIndexInfo);
        }
        //批量插入数据库
        if (CollectionUtils.isEmpty(infos)) {
            log.info("当前没有采集到数据，请选择在合理的时间点采集数据...");
            return;
        }
        log.info("当前数据记录数:{},内容:{}",infos.size(),infos);
//        int count = stockMarketIndexInfoMapper.insertBatch(infos);
//        log.info("当前插入了{}条数据",count);
    }

    /**
     * 定义批量获取分钟级股票数据
     */
    @Override
    public void getStockRtIndex() {
        //1.获取股票编码集合
        List<String> stockCodes = stockBusinessMapper.getAllStockCodes();
        //2.给股票编码添加交易所前缀 以6开头：sh 其他sz
        stockCodes = stockCodes.stream().map(stockCode -> {
            stockCode = stockCode.startsWith("6") ? "sh" + stockCode : "sz" + stockCode;
            return stockCode;
        }).collect(Collectors.toList());
        //2.组装请求对象
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer","http://finance.sina.com.cn/realstock/company/sh000001/nc.shtml");
        headers.add("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36");
        HttpEntity<Object> httpEntity = new HttpEntity<>(headers);
        //3.将集合分片处理 每片大小为15---》 15 15 10
        Lists.partition(stockCodes, 15).stream().forEach(itemList->{
                //1.组装url地址 地址格式是：http://hq.sinajs.cn/list=sh601003,sh601001
//                String url = stockInfoConfig.getMarketUrl()+String.join(",",itemList);
//                //3.发送数据 获取响应结果
//                ResponseEntity<String> respEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
//                //获取响应数据
//                String respStr = respEntity.getBody();
//                log.info("数据采集数据:{}",respStr);
//                //4.调用工具类解析响应的数据 并封装到集合下
//                List list = parserStockInfoUtil.parser4StockOrMarketInfo(respStr, ParseType.ASHARE);
//                log.info("当前采集的股票信息记录数:{}",list.size());
                //5.批量保存数据
//                int count = stockRtInfoMapper.insertBatch(list);
//                log.info("当前插入的记录条数:{}",count);
            //1.并发插入数据口数据 效率高 问题是1.线程复用性不强，存在线程被反复的构建和销毁
            //开销大 2.可能会存在主业务线程被挤压的情况 导致主业务线程饥渴
//            new Thread(()->{
//                //1.组装url地址 地址格式是：http://hq.sinajs.cn/list=sh601003,sh601001
//                String url = stockInfoConfig.getMarketUrl()+String.join(",",itemList);
//                //3.发送数据 获取响应结果
//                ResponseEntity<String> respEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
//                //获取响应数据
//                String respStr = respEntity.getBody();
//                log.info("数据采集数据:{}",respStr);
//                //4.调用工具类解析响应的数据 并封装到集合下
//                List list = parserStockInfoUtil.parser4StockOrMarketInfo(respStr, ParseType.ASHARE);
//                log.info("当前采集的股票信息记录数:{}",list.size());
//                //5.批量保存数据
//                int count = stockRtInfoMapper.insertBatch(list);
//                log.info("当前插入的记录条数:{}",count);
//            }).start();
            //2.使用线程池优化
            threadPoolTaskExecutor.submit(()->{
                //1.组装url地址 地址格式是：http://hq.sinajs.cn/list=sh601003,sh601001
                String url = stockInfoConfig.getMarketUrl()+String.join(",",itemList);
                //3.发送数据 获取响应结果
                ResponseEntity<String> respEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
                //获取响应数据
                String respStr = respEntity.getBody();
                log.info("数据采集数据:{}",respStr);
                //4.调用工具类解析响应的数据 并封装到集合下
                List list = parserStockInfoUtil.parser4StockOrMarketInfo(respStr, ParseType.ASHARE);
                log.info("当前采集的股票信息记录数:{}",list.size());
                //5.批量保存数据
                int count = stockRtInfoMapper.insertBatch(list);
                log.info("当前插入的记录条数:{}",count);
            });
        });
    }
}




